package com.strato.annotation.osgi.v1_0_0.service.util;

import java.lang.annotation.Annotation;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.List;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;

import com.strato.annotation.base.v1_0_0.handler.AnnotationHandler;
import com.strato.annotation.base.v1_0_0.lifecycle.BundleContextAware;
import com.strato.annotation.base.v1_0_0.lifecycle.ServiceLifeCycle;
import com.strato.annotation.osgi.v1_0_0.service.util.inline.OsgiMethodInterceptor;
import com.strato.base.aop.v1_0_0.AopFactory;
import com.strato.base.bean.v1_0_0.BeanUtil;
import com.strato.base.osgi.v1_0_0.BundleUtil;
import com.strato.logging.v1_0_0.api.Log;
import com.strato.logging.v1_0_0.api.LogFactory;


public class ServiceCreator {

	private static Log log = LogFactory.getLog(ServiceCreator.class);

	public static Object newInstance(Bundle bundle, Class<?> clazz) {
		Object instance = createProxy(clazz);
		for (Field field : BeanUtil.getFields(clazz)) {
			Class<?> fieldType = field.getType();
			if (!fieldType.isInterface() || field.getAnnotations() == null || field.getAnnotations().length == 0) {
				continue;
			}
			enhanceField(bundle, clazz, field, instance);
		}
		if (BundleContextAware.class.isInstance(instance)) {
			BundleContextAware aware = (BundleContextAware) instance;
			aware.setBundleContext(new WeakReference<BundleContext>(bundle.getBundleContext()));
		}
		if (ServiceLifeCycle.class.isInstance(instance)) {
			ServiceLifeCycle slc = (ServiceLifeCycle) instance;
			slc.init();
		}
		log.info("Created service instance:" + instance);
		return instance;
	}

	private static Object createProxy(Class<?> clazz) {
		return AopFactory.createProxy(clazz, OsgiMethodInterceptor.getInstance());
	}

	private static void enhanceField(Bundle bundle, Class<?> clazz, Field field, Object instance) {
		List<AnnotationHandler> handlers = BundleUtil.getServices(bundle.getBundleContext(), AnnotationHandler.class,
				null);
		for (AnnotationHandler handler : handlers) {
			for (Annotation fieldAnnotation : field.getAnnotations()) {
				handler.handleFieldOnInstantiate(bundle, field, clazz, instance, fieldAnnotation);
			}
		}
	}
}
